home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Applications / Newswatcher 2.0b22 / NW Source / Source / text.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-26  |  27.9 KB  |  1,180 lines  |  [TEXT/MMCC]

  1. /*----------------------------------------------------------------------------
  2.  
  3.     text.c
  4.  
  5.     This module handles read-only text windows.
  6.     
  7.     Copyright © 1994, Northwestern University.
  8.  
  9. ----------------------------------------------------------------------------*/
  10.  
  11. #include <string.h>
  12. #include <ctype.h>
  13.  
  14. #include "glob.h"
  15. #include "text.h"
  16. #include "menus.h"
  17. #include "tescroll.h"
  18. #include "url.h"
  19. #include "newswatcher.h"
  20. #include "drawutil.h"
  21. #include "windutil.h"
  22. #include "memutil.h"
  23. #include "dialog.h"
  24. #include "teutil.h"
  25. #include "wind.h"
  26. #include "about.h"
  27. #include "dragutil.h"
  28. #include "print.h"
  29. #include "status.h"
  30. #include "fileutil.h"
  31. #include "strutil.h"
  32. #include "sfutil.h"
  33. #include "group.h"
  34. #include "key.h"
  35. #include "ic.h"
  36.  
  37.  
  38.  
  39. #define kMinWindowWidth        410            /* minimum window width */
  40.  
  41.  
  42.  
  43. static TEClickLoopUPP gAutoScrollUPP;
  44. static ControlActionUPP gScrollActionUPP;
  45.  
  46.  
  47.  
  48. /*----------------------------------------------------------------------------
  49.     GetTextRect 
  50.     
  51.     Compute the "text" rectangle of a text window
  52.             
  53.     Entry:    wind = pointer to text window.
  54.             
  55.     Exit:    *textRect = text rectangle.
  56.     
  57.     The "text" rectangle is the area of the window where the text is 
  58.     displayed: the window portrect, minus the panel area, minus the scroll
  59.     bars, minus the text margin.
  60. ----------------------------------------------------------------------------*/
  61.  
  62. static void GetTextRect (WindowPtr wind, Rect *textRect)
  63. {
  64.     TWindow **info;
  65.  
  66.     info = (TWindow**)GetWRefCon(wind);
  67.     *textRect = wind->portRect;
  68.     textRect->top += (**info).panelHeight;
  69.     textRect->bottom -= 15;
  70.     textRect->right -= 15;
  71.     InsetRect(textRect, kTextMargin, kTextMargin);
  72. }
  73.  
  74.  
  75.  
  76. /*----------------------------------------------------------------------------
  77.     FixHeight 
  78.     
  79.     Round down window height to an exact multiple of lines.
  80.             
  81.     Entry:    wind = pointer to text window.
  82.             *height = window height.
  83.             
  84.     Exit:    *height = adjusted window height
  85. ----------------------------------------------------------------------------*/
  86.  
  87. static void FixHeight (WindowPtr wind, short *height)
  88. {
  89.     TWindow **info;
  90.     short panelHeight, lineHeight, adjust;
  91.  
  92.     info = (TWindow**)GetWRefCon(wind);
  93.     panelHeight = (**info).panelHeight;
  94.     lineHeight = GetFontLineHeight(wind);
  95.     adjust = panelHeight + 15 + 2*kTextMargin;
  96.     *height = (*height - adjust) / lineHeight * lineHeight + adjust;
  97. }
  98.  
  99.  
  100.  
  101. /*----------------------------------------------------------------------------
  102.     MinHeight 
  103.     
  104.     Compute the minimum height of a text window.
  105.             
  106.     Entry:    wind = pointer to text window.
  107. ----------------------------------------------------------------------------*/
  108.  
  109. static short MinHeight (WindowPtr wind)
  110. {
  111.     TWindow **info;
  112.     short lineHeight, height, extra;
  113.     
  114.     info = (TWindow**)GetWRefCon(wind);
  115.     lineHeight = GetFontLineHeight(wind);
  116.     extra = lineHeight + 15 + 2*kTextMargin;
  117.     if (extra < 65) extra = 65 + lineHeight;
  118.     height = (**info).panelHeight + extra;
  119.     FixHeight(wind, &height);
  120.     return height;
  121. }
  122.  
  123.  
  124.  
  125. /*----------------------------------------------------------------------------
  126.     ScrollAction 
  127.     
  128.     Vertical scroll bar action proc.
  129.  
  130.     Entry:    vScroll = handle to vertical scroll bar control.
  131.             part = part code.
  132. ----------------------------------------------------------------------------*/
  133.  
  134. static pascal void ScrollAction (ControlHandle vScroll, short part)
  135. {
  136.     WindowPtr wind;
  137.     TWindow **info;
  138.     TEHandle theTE;
  139.     
  140.     wind = (**vScroll).contrlOwner;
  141.     info = (TWindow**)GetWRefCon(wind);
  142.     theTE = (**info).theTE;
  143.     TEScrollScrollByPartCode(theTE, vScroll, part);
  144. }
  145.  
  146.  
  147.  
  148. /*----------------------------------------------------------------------------
  149.     AutoScroll 
  150.     
  151.     Handle text window autoscrolling.
  152.             
  153.     Exit:    function result = true
  154. ----------------------------------------------------------------------------*/
  155.  
  156. static pascal Boolean AutoScroll (void)
  157. {
  158.     WindowPtr wind;
  159.     TWindow **info;
  160.     ControlHandle vScroll;
  161.     TEHandle theTE;
  162.  
  163.     wind = MyFrontWindow();
  164.     if (wind == nil) return true;
  165.     info = (TWindow**)GetWRefCon(wind);
  166.     vScroll = (**info).vScroll;
  167.     theTE = (**info).theTE;
  168.     TEScrollAutoScroll(theTE, vScroll);
  169.     return true;
  170. }
  171.  
  172.  
  173.  
  174. /*----------------------------------------------------------------------------
  175.     ResizeContents 
  176.     
  177.     Adjust a text window's contents after a window size change (grow
  178.     or zoom).
  179.             
  180.     Entry:    wind = pointer to text window.
  181. ----------------------------------------------------------------------------*/
  182.  
  183. static void ResizeContents (WindowPtr wind)
  184. {
  185.     TWindow **info;
  186.     short width, height, panelHeight;
  187.     ControlHandle vScroll;
  188.     TEHandle theTE;
  189.     Rect r;
  190.  
  191.     info = (TWindow**)GetWRefCon(wind);
  192.     panelHeight = (**info).panelHeight;
  193.     vScroll = (**info).vScroll;
  194.     theTE = (**info).theTE;
  195.     width = wind->portRect.right;
  196.     height = wind->portRect.bottom;
  197.     
  198.     SetRect(&r, width-15, panelHeight-1, width+1, height-14);
  199.     (**vScroll).contrlRect = r;
  200.     
  201.     GetTextRect(wind, &r);
  202.     (**theTE).viewRect = (**theTE).destRect = r;
  203.     TECalText(theTE);
  204.     SetControlValue(vScroll, 0);
  205.     TEScrollAdjustScrollMax(theTE, vScroll);
  206.     TEScrollScrollSelectionIntoView(theTE, vScroll);
  207.     
  208.     InvalRect(&wind->portRect);
  209. }
  210.  
  211.  
  212.  
  213. /*----------------------------------------------------------------------------
  214.     MakeNewTextWindow
  215.     
  216.     Create a new text window.
  217.     
  218.     Entry:    title = window title, P-format.
  219.             panelHeight = panel height.
  220.             drawPanel = pointer to panel drawing function, or nil if none.
  221.             text = handle to text.
  222.                 
  223.     Exit:    function result = error code.
  224.             *theWindow = pointer to new window.
  225. ----------------------------------------------------------------------------*/
  226.  
  227. OSErr MakeNewTextWindow (StringPtr title, short panelHeight, 
  228.     void (*drawPanel)(WindowPtr), Handle text, WindowPtr *theWindow)
  229. {
  230.     short width, height;
  231.     WindowPtr wind = nil;
  232.     TWindow **info;
  233.     Rect r;
  234.     TEHandle theTE;
  235.     ControlHandle vScroll;
  236.     OSErr err = noErr;
  237.     char state;
  238.     GrafPtr port;
  239.     long len;
  240.     
  241.     MyICReadSharedPrefs(kICScreenFont);
  242.     
  243.     GetPort(&port);
  244.  
  245.     err = CreateNewWindow(kText, title, gPrefs.textFont, gPrefs.textSize, &wind);
  246.     if (err != noErr) return err;
  247.     SetPort(wind);
  248.     info = (TWindow**)GetWRefCon(wind);
  249.  
  250.     (**info).panelHeight = panelHeight;
  251.     (**info).drawPanel = drawPanel;
  252.     width = kMinWindowWidth;
  253.     height = MinHeight(wind);
  254.     PositionNewWindow(wind, width, height);
  255.  
  256.     GetTextRect(wind, &r);
  257.     theTE = TENew(&r, &r);
  258.     (**theTE).clickLoop = gAutoScrollUPP;
  259.     if (gHaveTEOutlineHilite) TEFeatureFlag(teFOutlineHilite, TEBitSet, theTE);
  260.     (**info).theTE = theTE;
  261.     
  262.     SetRect(&r, width-15, panelHeight-1, width+1, height-14); 
  263.     vScroll = NewControl(wind, &r, "\p", true, 0, 0, 0, scrollBarProc, 1);
  264.     (**info).vScroll = vScroll;
  265.     
  266.     state = MyHGetState(text);
  267.     MyHLock(text);
  268.     len = MyGetHandleSize(text);
  269.     if (len > 0x7fff) len = 0x7fff;
  270.     err = MyTESetText(*text, len, theTE);
  271.     MyHSetState(text, state);
  272.     if (err != noErr) goto exit;
  273.     
  274.     TESetSelect(0, 0, theTE);
  275.     
  276.     err = DoZoom(wind, inZoomOut);
  277.     if (err != noErr) goto exit;
  278.     
  279.     TEScrollAdjustScrollMax(theTE, vScroll);
  280.     MyShowWindow(wind);
  281.     *theWindow = wind;
  282.     SetPort(port);
  283.     return noErr;
  284.     
  285. exit:
  286.  
  287.     DoClose(wind);
  288.     SetPort(port);
  289.     return err;
  290. }
  291.  
  292.  
  293.  
  294. /*----------------------------------------------------------------------------
  295.     CheckTextWindowAlreadyOpen
  296.     
  297.     Check to see if a text window is already open, and if it is, bring it to
  298.     the front..
  299.     
  300.     Entry:    title = window title, P-format.
  301.                 
  302.     Exit:    function result = true if already open window brought to front.
  303. ----------------------------------------------------------------------------*/
  304.  
  305. Boolean CheckTextWindowAlreadyOpen (StringPtr title)
  306. {
  307.     WindowPtr wind;
  308.     Str255 windTitle;
  309.     TWindowKind kind;
  310.     
  311.     wind = FrontWindow();
  312.     while (wind != nil) {
  313.         kind = GetWindowKind(wind);
  314.         if (kind == kText) {
  315.             GetWTitle(wind, windTitle);
  316.             if (EqualString(windTitle, title, false, false)) {
  317.                 MySelectWindow(wind);
  318.                 return true;
  319.             }
  320.         }
  321.         wind = (WindowPtr)(((WindowPeek)wind)->nextWindow);
  322.     }
  323.     return false;
  324. }
  325.  
  326.  
  327.  
  328. /*----------------------------------------------------------------------------
  329.     Find 
  330.     
  331.     Search a text window for a pattern.
  332.             
  333.     Entry:    wind = pointer to text window.
  334.             offset = offset into text to begin search.
  335.             gFindPattern = pattern.
  336.     
  337.     Exit:    function result = error code.
  338. ----------------------------------------------------------------------------*/
  339.  
  340. static OSErr Find (WindowPtr wind, short offset)
  341. {
  342.     TWindow **info;
  343.     TEHandle theTE;
  344.     Handle hText;
  345.     short len;
  346.     char state;
  347.     long matchOffset;
  348.     OSErr err = noErr;
  349.     
  350.     info = (TWindow**)GetWRefCon(wind);
  351.     theTE = (**info).theTE;
  352.     hText = (**theTE).hText;
  353.     len = (**theTE).teLength - offset;
  354.     state = MyHGetState(hText);
  355.     MyHLock(hText);
  356.     err = MyNSubstringSearch(*hText+offset, gFindPattern, len, &matchOffset, 
  357.         GiveTime);
  358.     MyHSetState(hText, state);
  359.     if (err != noErr) return err;
  360.     if (matchOffset == -1) {
  361.         SysBeep(0);
  362.     } else {
  363.         offset += matchOffset;
  364.         TESetSelect(offset, offset + strlen(gFindPattern), theTE);
  365.         TEScrollScrollToMiddle(theTE, offset, (**info).vScroll);
  366.     }
  367.     return noErr;
  368. }
  369.  
  370.  
  371.  
  372. /*----------------------------------------------------------------------------
  373.     DoSave 
  374.     
  375.     Handle the "Save" command.
  376.             
  377.     Entry:    wind = pointer to text window.
  378.             modifiers = modifiers field from event record.
  379.     
  380.     Exit:    function result = error code.
  381. ----------------------------------------------------------------------------*/
  382.  
  383. static OSErr DoSave (WindowPtr wind, short modifiers)
  384. {
  385.     Str255 title;
  386.     Str31 fileName;
  387.     StandardFileReply reply;
  388.     Str255 prompt;
  389.     OSErr err = noErr;
  390.     TWindow **info;
  391.     Handle text;
  392.     long start, end;
  393.     TEHandle theTE;
  394.     char state;
  395.     short refNum = 0;
  396.     Boolean empty;
  397.     Boolean needCR;
  398.     long length;
  399.     char *p;
  400.     
  401.     MyICReadSharedPrefs(kICeditorHelper);
  402.  
  403.     GetWTitle(wind, title);
  404.     MakeLegalFileName(title, fileName);
  405.     GetPString(kStrSaveTextFilePrompt, prompt);
  406.     MyStandardPutFile(prompt, fileName, &reply,
  407.         gPrefs.savedArtDefaultFolder ? gPrefs.savedArtDefaultFolderAlias : nil);
  408.     if (!reply.sfGood) return userCanceledErr;
  409.     info = (TWindow**)GetWRefCon(wind);
  410.     theTE = (**info).theTE;
  411.     text = (**theTE).hText;
  412.     if ((modifiers & shiftKey) == 0) {
  413.         start = 0;
  414.         end = MyGetHandleSize(text);
  415.     } else {
  416.         start = (**theTE).selStart;
  417.         end = (**theTE).selEnd;
  418.     }
  419.     
  420.     state = MyHGetState(text);
  421.  
  422.     err = OpenDataForkWriteCreateIfMissing(&reply.sfFile, gPrefs.savedArtCreator, 'TEXT',
  423.         reply.sfScript, false, &refNum, &empty);
  424.     if (err != noErr) goto exit;
  425.  
  426.     length = end - start;
  427.     MyHLock(text);
  428.     
  429.     for (p = *text + end - 1; p >= *text + start && *p == CR; p--) /* do nothing */;
  430.     p++;
  431.     if (p < *text + end) {
  432.         needCR = false;
  433.         length = p + 1 - *text - start;
  434.     } else {
  435.         needCR = true;
  436.     }
  437.     
  438.     err = FSWrite(refNum, &length, *text + start);
  439.     if (err != noErr) goto exit;
  440.     if (needCR) {
  441.         length = 1;
  442.         err = FSWrite(refNum, &length, CRSTR);
  443.         if (err != noErr) goto exit;
  444.     }
  445.     MyHSetState(text, state);
  446.     MyFSClose(refNum, nil);
  447.     return noErr;
  448.     
  449. exit:
  450.  
  451.     MyHSetState(text, state);
  452.     if (refNum != 0) MyFSClose(refNum, nil);
  453.     return err;
  454. }
  455.  
  456.  
  457.  
  458. /*----------------------------------------------------------------------------
  459.     DoSaveAs
  460.     
  461.     Handle the "Save As" command.
  462.             
  463.     Entry:    wind = pointer to text window.
  464.             modifiers = modifiers field from event record.
  465.     
  466.     Exit:    function result = error code.
  467. ----------------------------------------------------------------------------*/
  468.  
  469. static OSErr DoSaveAs (WindowPtr wind, short modifiers)
  470. {
  471.     return DoSave(wind, modifiers);
  472. }
  473.  
  474.  
  475.  
  476. /*----------------------------------------------------------------------------
  477.     DoPrint 
  478.     
  479.     Handle the "Print" command.
  480.             
  481.     Entry:    wind = pointer to text window.
  482.             modifiers = modifiers field from event record.
  483.             
  484.     Exit:    function result = error code.
  485. ----------------------------------------------------------------------------*/
  486.  
  487. static OSErr DoPrint (WindowPtr wind, short modifiers)
  488. {
  489.     TWindow **info;
  490.     TEHandle theTE;
  491.     Handle text;
  492.     CStr255 title;
  493.     OSErr err = noErr;
  494.     long start, end;
  495.     
  496.     err = StartPrint();
  497.     if (err != noErr) return err;
  498.     
  499.     err = DisplayStatusMessageNumber(kStrPrinting);
  500.     if (err != noErr) return err;
  501.     
  502.     GetWTitle(wind, (StringPtr)title);
  503.     p2cstr((StringPtr)title);
  504.     
  505.     info = (TWindow**)GetWRefCon(wind);
  506.     theTE = (**info).theTE;
  507.     text = (**theTE).hText;
  508.     start = (**theTE).selStart;
  509.     end = (**theTE).selEnd;
  510.     if ((modifiers & shiftKey) == 0 || start >= end) {
  511.         start = 0;
  512.         end = MyGetHandleSize(text);
  513.     }
  514.     
  515.     return PrintText((**theTE).hText, start, end, title);
  516. }
  517.  
  518.  
  519.  
  520. /*----------------------------------------------------------------------------
  521.     DoCopy 
  522.     
  523.     Handle the "Copy" command.
  524.             
  525.     Entry:    wind = pointer to text window.
  526. ----------------------------------------------------------------------------*/
  527.  
  528. static void DoCopy (WindowPtr wind)
  529. {
  530.     TWindow **info;
  531.     TEHandle theTE;
  532.     
  533.     info = (TWindow**)GetWRefCon(wind);
  534.     theTE = (**info).theTE;
  535.     MyTECopy(theTE);
  536. }
  537.  
  538.  
  539.  
  540. /*----------------------------------------------------------------------------
  541.     DoSelectAll 
  542.     
  543.     Handle the "Select All" command.
  544.             
  545.     Entry:    wind = pointer to text window.
  546. ----------------------------------------------------------------------------*/
  547.  
  548. static void DoSelectAll (WindowPtr wind)
  549. {
  550.     TWindow **info;
  551.     TEHandle theTE;
  552.     
  553.     info = (TWindow**)GetWRefCon(wind);
  554.     theTE = (**info).theTE;
  555.     TESetSelect(0, 0x7fff, theTE);
  556. }
  557.  
  558.  
  559.  
  560. /*----------------------------------------------------------------------------
  561.     DoFind 
  562.     
  563.     Handle the "Find" command for a text window.
  564.             
  565.     Entry:    wind = pointer to text window.
  566.     
  567.     Exit:    function result = error code.
  568. ----------------------------------------------------------------------------*/
  569.  
  570. static OSErr DoFind (WindowPtr wind)
  571. {
  572.     TWindow **info;
  573.     TEHandle theTE;
  574.     OSErr err = noErr;
  575.     
  576.     err = DoFindDialog();
  577.     if (err != noErr) return err;
  578.     info = (TWindow**)GetWRefCon(wind);
  579.     theTE = (**info).theTE;
  580.     return Find(wind, gPrefs.startFindAtBeginning ? 0 : (**theTE).selStart);
  581. }
  582.  
  583.  
  584.  
  585. /*----------------------------------------------------------------------------
  586.     DoFindAgain
  587.     
  588.     Handle the "Find Again" command for a text window.
  589.             
  590.     Entry:    wind = pointer to text window.
  591.     
  592.     Exit:    function result = error code.
  593. ----------------------------------------------------------------------------*/
  594.  
  595. static OSErr DoFindAgain (WindowPtr wind)
  596. {
  597.     TWindow **info;
  598.     TEHandle theTE;
  599.     
  600.     info = (TWindow**)GetWRefCon(wind);
  601.     theTE = (**info).theTE;
  602.     return Find(wind, (**theTE).selEnd);
  603. }
  604.  
  605.  
  606.  
  607. /*----------------------------------------------------------------------------
  608.     DoEnterSelection
  609.     
  610.     Handle the "Enter Selection" command for a text window.
  611.             
  612.     Entry:    wind = pointer to text window.
  613.     
  614.     Exit:    function result = error code.
  615. ----------------------------------------------------------------------------*/
  616.  
  617. static OSErr DoEnterSelection (WindowPtr wind)
  618. {
  619.     TWindow **info;
  620.     TEHandle theTE;
  621.     short selStart, selEnd, len;
  622.     Handle hText;
  623.     
  624.     info = (TWindow**)GetWRefCon(wind);
  625.     theTE = (**info).theTE;
  626.     selStart = (**theTE).selStart;
  627.     selEnd = (**theTE).selEnd;
  628.     hText = (**theTE).hText;
  629.     if (selStart >= selEnd || selEnd > selStart + 255) return noErr;
  630.     len = selEnd - selStart;
  631.     BlockMoveData(*hText + selStart, gFindPattern, len);
  632.     gFindPattern[len] = 0;
  633.     return noErr;
  634. }
  635.  
  636.  
  637.  
  638. /*----------------------------------------------------------------------------
  639.     Activate 
  640.     
  641.     Handle an activate event for a text window.
  642.             
  643.     Entry:    wind = pointer to text window.
  644.             act = true to activate, false to deactivate
  645. ----------------------------------------------------------------------------*/
  646.  
  647. static void Activate (WindowPtr wind, Boolean act)
  648. {
  649.     TWindow **info;
  650.     TEHandle theTE;
  651.     ControlHandle vScroll;
  652.     Rect r;
  653.  
  654.     info = (TWindow**)GetWRefCon(wind);
  655.     theTE = (**info).theTE;
  656.     vScroll = (**info).vScroll;
  657.     if (act) {
  658.         ShowControl(vScroll);
  659.         TEActivate(theTE);
  660.     } else {
  661.         HideControl(vScroll);
  662.         TEDeactivate(theTE);
  663.     }
  664.     r = wind->portRect;
  665.     r.top = r.bottom - 15;
  666.     r.left = r.right - 15;
  667.     InvalRect(&r);
  668. }
  669.  
  670.  
  671.  
  672. /*----------------------------------------------------------------------------
  673.     Update 
  674.     
  675.     Handle an update event for a text window.
  676.             
  677.     Entry:    wind = pointer to text window.
  678. ----------------------------------------------------------------------------*/
  679.  
  680. static void Update (WindowPtr wind)
  681. {
  682.     TWindow **info;
  683.     short panelHeight, windWidth;
  684.     Rect r;
  685.     TEHandle theTE;
  686.  
  687.     info = (TWindow**)GetWRefCon(wind);
  688.     panelHeight = (**info).panelHeight;
  689.     theTE = (**info).theTE;
  690.     
  691.     r = wind->portRect;
  692.     r.top += panelHeight;
  693.     ClipRect(&r);
  694.     DrawGrowIcon(wind);
  695.     ClipRect(&wind->portRect);
  696.     
  697.     UpdateControls(wind, wind->visRgn);
  698.     
  699.     if (panelHeight > 0) {
  700.         (*(**info).drawPanel)(wind);
  701.         windWidth = wind->portRect.right - wind->portRect.left;
  702.         MoveTo(0, panelHeight-3);
  703.         LineTo(windWidth, panelHeight-3);
  704.         MoveTo(0, panelHeight-1);
  705.         LineTo(windWidth, panelHeight-1);
  706.     }
  707.     
  708.     TEUpdate(&wind->portRect, theTE);
  709. }
  710.  
  711.  
  712.  
  713. /*----------------------------------------------------------------------------
  714.     Mouse 
  715.     
  716.     Handle a mouse down event in the content area of a text window.
  717.             
  718.     Entry:    wind = pointer to text window.
  719.             where = location of mouse down in local coords.
  720.             modifiers = modifiers field from event record.
  721.             
  722.     Exit:    function result = error code.
  723. ----------------------------------------------------------------------------*/
  724.  
  725. static OSErr Mouse (WindowPtr wind, Point where, short modifiers)
  726. {
  727.     TWindow **info;
  728.     TEHandle theTE;
  729.     Rect viewRect;
  730.     short part, oldVal, dv;
  731.     ControlHandle control, vScroll;
  732.     OSErr err = noErr;
  733.     Boolean dragged, trashed;
  734.     short oldSelStart, oldSelEnd;
  735.  
  736.     info = (TWindow**) GetWRefCon(wind);
  737.     theTE = (**info).theTE;
  738.     vScroll = (**info).vScroll;
  739.     viewRect = (**theTE).viewRect;
  740.     InsetRect(&viewRect, -kTextMargin, 0);
  741.     part = FindControl(where, wind, &control);
  742.     if (part != 0 && control == vScroll) {
  743.         if (part == inThumb) {
  744.             oldVal = GetControlValue(vScroll);
  745.             TrackControl(vScroll, where, nil);
  746.             dv = GetControlValue(vScroll) - oldVal;
  747.             if (dv != 0) TEScrollScrollText(theTE, vScroll, -dv);
  748.         } else {
  749.                 SetControlReference(vScroll, 0);
  750.                 TrackControl(vScroll, where, gScrollActionUPP);
  751.                 SetControlReference(vScroll, 1);
  752.                 TEScrollAdjustScrollMax(theTE, vScroll);
  753.         }
  754.     } else if (PtInRect(where, &viewRect)) {
  755.         err = DragText(&gCurEvent, where, theTE, &dragged, &trashed);
  756.         if (err != noErr) return err;
  757.         if (wind == FrontWindow() && !dragged) {
  758.             oldSelStart = (**theTE).selStart;
  759.             oldSelEnd = (**theTE).selEnd;
  760.             TEClick(where, (modifiers & shiftKey) != 0, theTE);
  761.             err = CommandClick(wind, theTE, oldSelStart, oldSelEnd, modifiers);
  762.             if (err != noErr) return err;
  763.         }
  764.      } else if (where.v < (**info).panelHeight) {
  765.          CheckAboutWindowEasterEgg(wind, where, modifiers);
  766.      }
  767.      return noErr;
  768. }
  769.  
  770.  
  771.  
  772. /*----------------------------------------------------------------------------
  773.     Draggable
  774.     
  775.     Determine whether a mouse down event is on a draggable object in a 
  776.     text window.
  777.     
  778.     Entry:    wind = pointer to text window.
  779.             where = location of mouse down event, in local coordinates.
  780.             modifiers = modifiers field from event record.
  781.             
  782.     Exit:    function result = true if object is draggable.
  783. ----------------------------------------------------------------------------*/
  784.  
  785. static Boolean Draggable (WindowPtr wind, Point where, short modifiers)
  786. {
  787.     TWindow **info;
  788.     TEHandle theTE;
  789.     
  790.     info = (TWindow**)GetWRefCon(wind);
  791.     theTE = (**info).theTE;
  792.     return PtInTEHiliteRgn(where, theTE);
  793. }
  794.  
  795.  
  796.  
  797. /*----------------------------------------------------------------------------
  798.     Key 
  799.     
  800.     Handle a key down event for a text window.
  801.             
  802.     Entry:    wind = pointer to text window.
  803.             theChar = ASCII code of key.
  804.             theKey = keyboard code of key.
  805.             modifiers = modifiers field from event record.
  806.             
  807.     Exit:    function result = error code.
  808. ----------------------------------------------------------------------------*/
  809.  
  810. static OSErr Key (WindowPtr wind, unsigned char theChar, unsigned char theKey, 
  811.     short modifiers)
  812. {
  813.     TWindow **info;
  814.     ControlHandle vScroll;
  815.     TEHandle theTE;
  816.     OSErr err = noErr;
  817.     short scrollIntoView;
  818.     TKeypadKey keypadKey;
  819.     Boolean isArrow;
  820.  
  821.     info = (TWindow**)GetWRefCon(wind);
  822.     vScroll = (**info).vScroll;
  823.     theTE = (**info).theTE;
  824.     isArrow = IsArrowKey(theChar);
  825.     
  826.     if ((modifiers & cmdKey) != 0 && !isArrow) {
  827.         SysBeep(0);
  828.         return noErr;
  829.     }
  830.  
  831.     if (gPrefs.keypadShortcuts && IsKeypadKey(theChar, theKey, &keypadKey)) {
  832.         switch (keypadKey) {
  833.             case kKeypadEqualKey:
  834.                 DoSelectAll(wind);
  835.                 return noErr;
  836.             case kKeypadStarKey:
  837.                 return DoClose(wind);
  838.             case kKeypad1Key:
  839.                 TEScrollScrollByPartCode(theTE, vScroll, kScrollToEnd);
  840.                 return noErr;
  841.             case kKeypad2Key:
  842.                 TEScrollScrollByPartCode(theTE, vScroll, inDownButton);
  843.                 return noErr;
  844.             case kKeypad3Key:
  845.                 TEScrollScrollByPartCode(theTE, vScroll, inPageDown);
  846.                 return noErr;
  847.             case kKeypad7Key:
  848.                 TEScrollScrollByPartCode(theTE, vScroll, kScrollToHome);
  849.                 return noErr;
  850.             case kKeypad8Key:
  851.                 TEScrollScrollByPartCode(theTE, vScroll, inUpButton);
  852.                 return noErr;
  853.             case kKeypad9Key:
  854.                 TEScrollScrollByPartCode(theTE, vScroll, inPageUp);
  855.                 return noErr;
  856.             default:
  857.                 SysBeep(0);
  858.                 return noErr;
  859.         }
  860.     }
  861.     
  862.     if (theChar == pageUpKey) {
  863.         TEScrollScrollByPartCode(theTE, vScroll, inPageUp);
  864.         return noErr;
  865.     }
  866.     if (theChar == pageDownKey) {
  867.         TEScrollScrollByPartCode(theTE, vScroll, inPageDown);
  868.         return noErr;
  869.     }
  870.     if (theChar == homeKey) {
  871.         TEScrollScrollByPartCode(theTE, vScroll, kScrollToHome);
  872.         return noErr;
  873.     }
  874.     if (theChar == endKey) {
  875.         TEScrollScrollByPartCode(theTE, vScroll, kScrollToEnd);
  876.         return noErr;
  877.     }
  878.     
  879.     if (isArrow) {
  880.         TEArrowKey(theChar, modifiers, theTE, 0, &gPrevEvent, &scrollIntoView);
  881.         TEScrollScrollRangeIntoView(theTE, scrollIntoView, scrollIntoView, vScroll);
  882.         return noErr;
  883.     }
  884.     
  885.     if (gPrefs.keyboardShortcuts) {
  886.         theChar = tolower(theChar);
  887.         if (theChar == 'a') {
  888.             DoSelectAll(wind);
  889.             return noErr;
  890.         }
  891.     }
  892.  
  893.     SysBeep(0);
  894.     
  895.     return noErr;
  896. }
  897.  
  898.  
  899.  
  900. /*----------------------------------------------------------------------------
  901.     Grow 
  902.     
  903.     Handle a mouse down event in the grow box of a text window.
  904.     
  905.     Entry:    wind = pointer to text window.
  906.             where = location of mouse down event, in global coordinates.
  907.             
  908.     Exit:    function result = error code.
  909. ----------------------------------------------------------------------------*/
  910.  
  911. static OSErr Grow (WindowPtr wind, Point where)
  912. {
  913.     Rect sizeRect;
  914.     long size;
  915.     short width, height;
  916.     
  917.     SetRect(&sizeRect, kMinWindowWidth, MinHeight(wind), 0x7fff, 0x7fff);
  918.     size = GrowWindow(wind, where, &sizeRect);
  919.     
  920.     if (size  != 0) {
  921.         width = LoWord(size);
  922.         height = HiWord(size);
  923.         FixHeight(wind, &height);
  924.         SizeWindow(wind, width, height, false);
  925.         ResizeContents(wind);
  926.     }
  927.     
  928.     return noErr;
  929. }
  930.  
  931.  
  932.  
  933. /*----------------------------------------------------------------------------
  934.     Zoom
  935.     
  936.     Zoom a text window.
  937.     
  938.     Entry:    wind = pointer to text window.
  939.             zoomDir = zoom direction = inZoomIn or inZoomOut.
  940.             
  941.     Exit:    function result = error code.
  942. ----------------------------------------------------------------------------*/
  943.  
  944. static OSErr Zoom (WindowPtr wind, short zoomDir)
  945. {
  946.     TWindow **info;
  947.     short width, height, lineHeight, minHeight;
  948.     Rect zoomRect, r;    
  949.     WStateData **wState;
  950.     FontInfo fInfo;
  951.     TEHandle theTE, tempTE;
  952.     Handle tempHandle;
  953.     long longHeight;
  954.  
  955.     wState = (WStateData**)((WindowPeek)wind)->dataHandle;
  956.     if (zoomDir == inZoomOut) {
  957.         info = (TWindow**)GetWRefCon(wind);
  958.         GetFontInfo(&fInfo);
  959.         lineHeight = fInfo.leading + fInfo.ascent + fInfo.descent;
  960.         theTE = (**info).theTE;
  961.         
  962.         width = 75*CharWidth('a') + 2*kTextMargin + 18;
  963.         if (width < kMinWindowWidth) width = kMinWindowWidth;
  964.         
  965.         CalculateZoomRect(wind, width, 0x7fff, &zoomRect, gPrefs.dontCoverFinderIcons);
  966.         SetRect(&r, 0, 0, zoomRect.right - zoomRect.left - 15 - 2*kTextMargin, 0x7fff);
  967.         tempTE = TENew(&r, &r);
  968.         tempHandle = (**tempTE).hText;
  969.         (**tempTE).hText = (**theTE).hText;
  970.         TECalText(tempTE);
  971.         longHeight = (long)TEScrollNumTELines(tempTE) * (long)lineHeight;
  972.         longHeight += (**info).panelHeight + 15 + 2*kTextMargin;
  973.         (**tempTE).hText = tempHandle;
  974.         TEDispose(tempTE);
  975.         if (longHeight > 0x7fff) {
  976.             height = 0x7fff;
  977.         } else {
  978.             height = longHeight;
  979.             minHeight = MinHeight(wind);
  980.             if (height < minHeight) height = minHeight;
  981.         }
  982.         
  983.         CalculateZoomRect(wind, width, height, &zoomRect, gPrefs.dontCoverFinderIcons);
  984.         height = zoomRect.bottom - zoomRect.top;
  985.         FixHeight(wind, &height);
  986.         zoomRect.bottom = zoomRect.top + height;
  987.         (**wState).stdState = zoomRect;
  988.         if (WindRectEqualRect(wind, &zoomRect)) return noErr;
  989.     }
  990.     
  991.     EraseRect(&wind->portRect);
  992.     ZoomWindow(wind, zoomDir, false);
  993.     ResizeContents(wind);
  994.     return noErr;
  995. }
  996.  
  997.  
  998.  
  999. /*----------------------------------------------------------------------------
  1000.     Command 
  1001.     
  1002.     Handle a command for a text window.
  1003.             
  1004.     Entry:    wind = pointer to text window.
  1005.             menu = the menu.
  1006.             item = the item.
  1007.             modifiers = modifiers field from event record.
  1008.     
  1009.     Exit:    function result = error code.
  1010. ----------------------------------------------------------------------------*/
  1011.  
  1012. static OSErr Command (WindowPtr wind, short menu, short item, short modifiers)
  1013. {
  1014.     OSErr err = noErr;
  1015.  
  1016.     switch (menu) {
  1017.     
  1018.         case kFileMenu:
  1019.         
  1020.             switch (item) {
  1021.                 case kSaveItem:
  1022.                     err = DoSave(wind, modifiers);
  1023.                     break;
  1024.                 case kSaveAsItem:
  1025.                     err = DoSaveAs(wind, modifiers);
  1026.                     break;
  1027.                 case kPrintItem:
  1028.                     err = DoPrint(wind, modifiers);
  1029.                     break;
  1030.             }
  1031.             break;
  1032.             
  1033.         case kEditMenu:
  1034.  
  1035.             switch (item) {
  1036.                 case kCopyItem:
  1037.                     DoCopy(wind);
  1038.                     break;
  1039.                 case kSelectAllItem:
  1040.                     DoSelectAll(wind);
  1041.                     break;
  1042.                 case kFindItem:
  1043.                     err = DoFind(wind);
  1044.                     break;
  1045.                 case kFindAgainItem:
  1046.                     err = DoFindAgain(wind);
  1047.                     break;
  1048.                 case kEnterSelectionItem:
  1049.                     err = DoEnterSelection(wind);
  1050.                     break;
  1051.             }
  1052.             break;
  1053.      }
  1054.      
  1055.      return err;
  1056. }
  1057.  
  1058.  
  1059.  
  1060. /*----------------------------------------------------------------------------
  1061.     Close 
  1062.     
  1063.     Close a text window.
  1064.             
  1065.     Entry:    wind = pointer to text window.
  1066.     
  1067.     Exit:    function result = error code.
  1068. ----------------------------------------------------------------------------*/
  1069.  
  1070. static OSErr Close (WindowPtr wind)
  1071. {
  1072.     TWindow **info;
  1073.  
  1074.     info = (TWindow**)GetWRefCon(wind);
  1075.     
  1076.     if ((**info).theTE != nil) TEDispose((**info).theTE);
  1077.     MyDisposeHandle(info);
  1078.     MyDisposeWindow(wind);
  1079.     return noErr;
  1080. }
  1081.  
  1082.  
  1083.  
  1084. /*----------------------------------------------------------------------------
  1085.     Idle 
  1086.     
  1087.     Handle idle time tasks for a text window.
  1088.             
  1089.     Entry:    wind = pointer to text window.
  1090.     
  1091.     Exit:    cursorRgn = cursor region for WaitNextEvent mouse moved events.
  1092. ----------------------------------------------------------------------------*/
  1093.  
  1094. static void Idle (WindowPtr wind, RgnHandle cursorRgn)
  1095. {
  1096.     TWindow **info;
  1097.     TEHandle theTE;
  1098.     Rect r;
  1099.     Point where;
  1100.     unsigned long fileEnabled, editEnabled, specialEnabled;
  1101.     short selStart, selEnd;
  1102.  
  1103.     info = (TWindow**)GetWRefCon(wind);
  1104.     theTE = (**info).theTE;
  1105.     TEIdle(theTE);
  1106.     
  1107.     r = (**theTE).viewRect;
  1108.     InsetRect(&r, -kTextMargin, 0);
  1109.     LocalToGlobalRect(&r);
  1110.     RectRgn(cursorRgn, &r);
  1111.     if (gHaveDragMgr) SubtractTEHiliteRgn(cursorRgn, theTE);
  1112.     GetMouse(&where);
  1113.     LocalToGlobal(&where);
  1114.     if (PtInRgn(where, cursorRgn)) {
  1115.         SetCursor(&gIBeamCurs);
  1116.     } else {
  1117.         SetCursor(&qd.arrow);
  1118.         ComplementRgn(cursorRgn);
  1119.     }
  1120.     
  1121.     editEnabled = kTextEditEnabled;
  1122.     if (*gFindPattern == 0) editEnabled &= ~kFindAgainMask;
  1123.     selStart = (**theTE).selStart;
  1124.     selEnd = (**theTE).selEnd;
  1125.     if (selStart >= selEnd) {
  1126.         editEnabled &= ~(kCopyMask | kEnterSelectionMask);
  1127.     } else if (selEnd > selStart + 255) {
  1128.         editEnabled &= ~kEnterSelectionMask;
  1129.     }
  1130.     if (gStartupOK) {
  1131.         specialEnabled = kTextSpecialEnabled;
  1132.         if (!IsURL(theTE)) specialEnabled &= ~kOpenURLMask;
  1133.         SetMenusTo(kAppleAllEnabled, kTextFileEnabled, editEnabled, 
  1134.             kTextNewsEnabled, specialEnabled, kTextWindEnabled);
  1135.     } else {
  1136.         fileEnabled = kTextFileEnabled;
  1137.         fileEnabled &= ~(kNewGroupWindowMask | kOpenMask);
  1138.         SetMenusTo(kAppleAllEnabled, fileEnabled, editEnabled,
  1139.             kStartupBadNewsEnabled, kStartupBadSpecialEnabled, kStartupBadWindEnabled);
  1140.     }
  1141.     
  1142.     /* For shooting screen shots of menus with all items enabled. */
  1143.        
  1144.     #ifdef kDevelopmentVersion
  1145.     {
  1146.         unsigned long all = 0xffffffff;
  1147.         SetMenusTo(all, all, all, all, all, all);
  1148.     }
  1149.     #endif
  1150. }
  1151.  
  1152.  
  1153.  
  1154. /*----------------------------------------------------------------------------
  1155.     InitTextDispatchTable 
  1156.     
  1157.     Initialize the dispatch table for text windows.
  1158. ----------------------------------------------------------------------------*/
  1159.  
  1160. void InitTextDispatchTable (void)
  1161. {
  1162.     TDispatch *d;
  1163.     
  1164.     d = &gDispatch[kText];
  1165.     
  1166.     d->activate = Activate;
  1167.     d->update = Update;
  1168.     d->mouse = Mouse;
  1169.     d->draggable = Draggable;
  1170.     d->key = Key;
  1171.     d->grow = Grow;
  1172.     d->zoom = Zoom;
  1173.     d->command = Command;
  1174.     d->close = Close;
  1175.     d->idle = Idle;
  1176.     
  1177.     gAutoScrollUPP = NewTEClickLoopProc(AutoScroll);
  1178.     gScrollActionUPP = NewControlActionProc(ScrollAction);
  1179. }
  1180.